<template>
  <div class="chat-container">
    <div class="heard">
      <p v-if="stats.scope === stats.chatEnum.PRIVATE_CHAT">
        {{ JSON.parse(friend).note ?? JSON.parse(friend).fromName }}
      </p>
      <p v-else>
        {{ stats.team.teamName }}
      </p>
    </div>
    <div class="content" ref="chatRoom" v-html="stats.content"></div>
    <div class="send">
      <textarea
        placeholder="输入聊天内容...."
        v-model="stats.text"
        @keyup.enter="send"
        class="input-text"
      ></textarea>
      <van-button
        v-if="stats.text && stats.text.trim().length != 0"
        class="send-button"
        @click="send"
      >
        发送
      </van-button>
    </div>
  </div>
</template>
<script setup lang="ts">
import { showFailToast } from "vant";
import { inject, nextTick, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import myAxios from "../plugins/myAxios";
import { getCurrentUser } from "../services/user";
import moment from "moment";
import { ChatType } from "../models/chat";

const stats = ref({
  user: {
    id: 0,
    username: "",
    avatarUrl: "",
  },
  users: [],
  chatUser: {
    id: 0,
  },
  chatEnum: {
    PRIVATE_CHAT: 1,
    TEAM_CHAT: 2,
    HALL_CHAT: 3,
  },
  scope: 0,
  team: {
    teamId: 999,
    teamName: "",
  },
  text: "",
  messages: [],
  content: "",
});

let socket: WebSocket | null = null;
const heartbeatInterval = 60 * 1000; // 60秒
let heartbeatTimer: string | number | NodeJS.Timer | null | undefined = null;
const startHeartbeat = () => {
  heartbeatTimer = setInterval(() => {
    if (socket.readyState === WebSocket.OPEN) {
      socket.send("PING");
    }
  }, heartbeatInterval);
};

const stopHeartbeat = () => {
  clearInterval(heartbeatTimer);
  heartbeatTimer = null;
};

const route = useRoute();
stats.value.chatUser.id = Number(route.query.friendId);
const scope = Number(route.query.scope);
const teamId = route.query.teamId;
const teamName = route.query.teamName;
const chatRoom = ref(null);
const privateMessage = ref([] as ChatType[]);
onMounted(async () => {
  stats.value.user = await getCurrentUser("1");
  stats.value.team.teamId = teamId;
  stats.value.team.teamName = teamName;
  if (scope === stats.value.chatEnum.PRIVATE_CHAT) {
    stats.value.scope = stats.value.chatEnum.PRIVATE_CHAT;
    // 获取私聊消息记录
    if (stats.value.scope === stats.value.chatEnum.PRIVATE_CHAT) {
      const res = await myAxios.get("/chat/privateChat", {
        params: {
          toId: stats.value.user.id,
          fromId: stats.value.chatUser.id,
        },
      });
      if (res.code === 0 && res.data) {
        privateMessage.value = res.data;
      }
      privateMessage.value.forEach((chat) => {
        if (chat.fromId === stats.value.user.id) {
          createContent(
            true,
            chat.fromName,
            chat.fromUrl,
            chat.text,
            null,
            chat.createTime,
            chat.status
          );
        } else {
          createContent(
            false,
            chat.fromName,
            chat.fromUrl,
            chat.text,
            null,
            chat.createTime,
            null
          );
        }
      });
    }
  } else if (scope === stats.value.chatEnum.TEAM_CHAT) {
    stats.value.scope = stats.value.chatEnum.TEAM_CHAT;
    const teamMessage = ref([] as ChatType[]);
    const res = await myAxios.get("/chat/teamChat", {
      params: {
        teamId: stats.value.team.teamId,
        userId: stats.value.user.id,
      },
    });
    if (res.code === 0) {
      teamMessage.value = res.data;
    }
    teamMessage.value.forEach((chat) => {
      if (chat.fromId === stats.value.user.id) {
        createContent(
          true,
          chat.fromName,
          chat.fromUrl,
          chat.text,
          null,
          chat.createTime,
          null
        );
      } else {
        createContent(
          false,
          chat.fromName,
          chat.fromUrl,
          chat.text,
          null,
          chat.createTime,
          null
        );
      }
    });
  }
  init();
  // 内容始终显示最下方
  await nextTick();
  const lastElement = chatRoom.value.lastElementChild;
  if (lastElement !== null) {
    lastElement.scrollIntoView();
  }
});

const reload = inject("reload"); //刷新函数
const init = () => {
  let uid = stats.value.user.id;
  if (typeof WebSocket == "undefined") {
    showFailToast("小智遗憾告知:您的浏览器不支持WebSocket");
  } else {
    const isDev = process.env.NODE_ENV === "development";
    let socketUrl = isDev
      ? `ws://localhost:8081/api/websocket/${stats.value.user.id}/${stats.value.team.teamId}`
      : `wss://gouhuo-backend.allbugs.top:8081/api/websocket/${stats.value.user.id}/${stats.value.team.teamId}`;
    if (socket != null) {
      socket.close();
      socket = null;
    }
    // 开启一个websocket服务
    socket = new WebSocket(socketUrl);
    //打开事件
    socket.onopen = function () {
      startHeartbeat();
      // console.log("websocket已打开");
    };
    // 浏览器端收消息，获得从服务端发送过来的文本消息
    socket.onmessage = function (msg) {
      if (msg.data === "pong") {
        return;
      }
      // 对收到的json数据进行解析，
      const data = JSON.parse(msg.data);
      if (data.error) {
        showFailToast(`小智遗憾告知:${data.error}`);
        return;
      }
      stats.value.messages.push(data);
      reload();
      // 构建消息内容
      createContent(
        false,
        data.fromName,
        data.fromUrl,
        data.text,
        data.isAdmin,
        data.createTime,
        null
      );
    };
    //关闭事件
    socket.onclose = function () {
      // console.log("websocket已关闭");
      stopHeartbeat();
      setTimeout(init, 5000); // 5秒后重连
    };
    //发生了错误事件
    socket.onerror = function () {
      // console.log("websocket发生了错误");
    };
  }
};

const friendly = route.query.friendly;
const send = () => {
  if (stats.value.chatUser.id === 0) {
    return;
  }
  if (scope === 1 && stats.value.chatUser.id === stats.value.user.id) {
    showFailToast("小智遗憾告知:不能给自己发信息");
    return;
  }
  if (scope === 1 && !friendly && privateMessage.value.length >= 10) {
    showFailToast("小智遗憾告知:非好友只能聊十句");
    return;
  }
  if (!stats.value.text.trim()) {
    return;
  } else {
    if (typeof WebSocket == "undefined") {
      showFailToast("小智遗憾告知:您的浏览器不支持WebSocket");
    } else {
      console.log("您的浏览器支持WebSocket");
      if (teamId) {
        const teamMessage = {
          teamId: stats.value.team.teamId,
          teamName: stats.value.team.teamName,
          fromId: stats.value.user.id,
          fromName: stats.value.user.username,
          fromUrl: stats.value.user.avatarUrl,
          text: stats.value.text,
          createTime: new Date(),
          scope: 2,
          type: 0,
        };
        socket.send(JSON.stringify(teamMessage));
      } else {
        const priMessage = {
          toId: stats.value.chatUser.id,
          fromId: stats.value.user.id,
          fromName: stats.value.user.username,
          fromUrl: stats.value.user.avatarUrl,
          text: stats.value.text,
          createTime: new Date(),
          scope: 1,
          status: 0,
          type: 0,
        };
        socket.send(JSON.stringify(priMessage));
      }
      stats.value.messages.push({
        user: stats.value.user.id,
        text: stats.value.text,
      });
      createContent(
        true,
        stats.value.user.username,
        stats.value.user.avatarUrl,
        stats.value.text,
        null,
        null,
        null
      );
      stats.value.text = "";
      nextTick(() => {
        const lastElement = chatRoom.value.lastElementChild;
        lastElement.scrollIntoView();
      });
    }
  }
};

const router = useRouter();
const friend = route.query.friendInfo;
const friendDetail = (type: number) => {
  if (!friend) {
    router.back();
  } else {
    router.push({
      path: "/user",
      query: {
        friendInfo: type === 0 ? friend : null,
      },
    });
  }
};

/**
 * 这个方法是用来将 json的聊天消息数据转换成 html的。
 */
const createContent = (
  isMine: boolean,
  username: string,
  avatarUrl: string,
  text: string,
  isAdmin: boolean,
  createTime: Date,
  status: number
) => {
  // 当前用户消息
  let html;
  if (isMine) {
    // nowUser 表示是否显示当前用户发送的聊天消息，绿色气泡
    html = `
    <div class="message self">
      <div class="chatStatus">${
        teamId ? "" : !status || status === 0 ? "送达" : "已读"
      }</div>
    <div class="myInfo info">
      <img :alt=${username} class="avatar" onclick="friendDetail(1)" src=${avatarUrl}>
    </div>
      <p class="text">${text}</p>
    </div>
`;
  } else {
    // remoteUser表示远程用户聊天消息,灰色的气泡
    html = `
     <div class="message other">
      <img :alt=${username} class="avatar" onclick="friendDetail(0)" src=${avatarUrl}>
    <div class="info">
      <span class="username">${username}&nbsp;&nbsp;&nbsp;&nbsp;${moment(
      createTime
    ).format("YYYY-MM-DD HH:mm")}</span>
      <p class="${isAdmin ? "admin text" : "text"}" >${text}</p>
    </div>
    </div>
`;
  }
  stats.value.content += html;
};
/**
 * 模板字符串事件
 */
window.friendDetail = (type: number) => {
  friendDetail(type);
};
</script>
<style>
@import "../assets/css/chat.css";
</style>
